<?php

namespace fast;

use app\common\library\Auth;
use app\common\model\Attachment;
use Aws\S3\S3Client;
use Minio\Object\ObjectClient;
use think\File;
use think\helper\Str;
use think\Hook;

class MinioServer
{
    private static $instance = null;

    private array $config = [
        'key' => '1tLWS3Mvyz3cZl4DZRNg',
        'secret' => 'ZAKIFfUKCH1BbVtF9FKo8DMIPaio4LLvOy6YnH5u',
        'region' => 'zh-southeast',
        'version' => 'latest',
        'endpoint' => 'http://127.0.0.1:9990',
        'bucket' => 'comic',
    ];

    private function __construct(array $options = [])
    {
        $this->config = array_merge($this->config, $options);
    }


    public static function getInstance(): self
    {
        if (is_null(self::$instance)) {
            self::$instance = new self(config('minio'));
        }
        return self::$instance;
    }

    public function putObjectByFile(File $file): object
    {
        $objectClient = new ObjectClient($this->config);
        $fileName = $file->getInfo('name');
        $fileNameInfo = explode('.', $fileName);
        $fileExtend = end($fileNameInfo);
        $fileMd5Name = md5($fileName);
        $savePath = sprintf("/upload/%s/%s.%s", date('Y-m-d'), $fileMd5Name, $fileExtend);
        //获取后缀
        $objectClient->getS3Client()->putObject(
            [
                'Bucket' => $this->config['bucket'],
                'Key' => $savePath,
                'SourceFile' => $file->getRealPath(),
                'ContentType' => $file->getMime(),
            ]
        );
        $key = $savePath;
        $auth = Auth::instance();
        if ($key === false) {
            throw new \Exception("上传文件失败");
        }
        $category = request()->post('category');
        $category = array_key_exists($category, config('site.attachmentcategory') ?? []) ? $category : '';
        $fileInfo = $file->getInfo();
        $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
        $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
        $params = array(
            'admin_id' => (int)session('admin.id'),
            'user_id' => (int)$auth->id,
            'filename' => mb_substr(htmlspecialchars(strip_tags($fileInfo['name'])), 0, 100),
            'category' => $category,
            'filesize' => $fileInfo['size'],
            'imagewidth' => $fileInfo['imagewidth'] ?? 0,
            'imageheight' => $fileInfo['imageheight'] ?? 0,
            'imagetype' => $suffix,
            'imageframes' => 0,
            'mimetype' => $fileInfo['type'],
            'url' => $key,
            'uploadtime' => time(),
            'storage' => 'local',
            'sha1' => $file->hash(),
            'extparam' => '',
        );
        $attachment = new Attachment();
        $attachment->data(array_filter($params));
        $attachment->save();

        Hook::listen("upload_after", $attachment);
        return $attachment;
    }

    public function putObjectByFilePath(string $path): object
    {
        $file = new File($path);
        $file->setUploadInfo(array(
            'name' => basename($path),
            'size' => filesize($path),
            'type' => mime_content_type($path),
        ));
        $objectClient = new ObjectClient($this->config);
        $objectClient = $objectClient->setS3Client(new S3Client([
            'credentials' => [
                'key' => $this->config['key'],
                'secret' => $this->config['secret'],
            ],
            'region' => $this->config['region'],
            'version' => $this->config['version'],
            'endpoint' => $this->config['endpoint'],
            'use_path_style_endpoint' => true, //minio必须开启
            'http' => [
                'timeout' => 120,
            ]
        ]));
        $fileName = sprintf('%s%s', Str::random(20), $file->getInfo('name'));
        $fileNameInfo = explode('.', $fileName);
        $fileExtend = end($fileNameInfo);
        $fileMd5Name = md5($fileName);
        $savePath = sprintf("/upload/%s/%s.%s", date('Y-m-d'), $fileMd5Name, $fileExtend);
        //获取后缀
        $objectClient->getS3Client()->putObject(
            [
                'Bucket' => $this->config['bucket'],
                'Key' => $savePath,
                'SourceFile' => $file->getRealPath(),
                'ContentType' => $file->getMime(),
            ]
        );
        $key = $savePath;
        $auth = Auth::instance();
        if ($key === false) {
            throw new \Exception("上传文件失败");
        }
        $category = request()->post('category');
        $category = array_key_exists($category, config('site.attachmentcategory') ?? []) ? $category : '';
        $fileInfo = $file->getInfo();
        $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
        $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
        $params = array(
            'admin_id' => (int)session('admin.id'),
            'user_id' => (int)$auth->id,
            'filename' => mb_substr(htmlspecialchars(strip_tags($fileInfo['name'])), 0, 100),
            'category' => $category,
            'filesize' => $fileInfo['size'],
            'imagewidth' => $fileInfo['imagewidth'] ?? 0,
            'imageheight' => $fileInfo['imageheight'] ?? 0,
            'imagetype' => $suffix,
            'imageframes' => 0,
            'mimetype' => $fileInfo['type'],
            'url' => $key,
            'uploadtime' => time(),
            'storage' => 'local',
            'sha1' => $file->hash(),
            'extparam' => '',
        );
        $attachment = new Attachment();
        $attachment->data(array_filter($params));
        $attachment->save();

        Hook::listen("upload_after", $attachment);
        return $attachment;
    }

    public function getObjectUri(string $objectName): string
    {
        $objectClient = new ObjectClient($this->config);
        return $objectClient->getObjectUrl($objectName);
    }
}